C:\ftp\openSmtp\alexds_OpenSmtp_src\MailEncoder.cs
namespace OpenSmtp.Mail
{

(*)	/******************************************************************************
(*)		Copyright 2001, 2002, 2003 Ian Stallings
(*)		OpenSmtp.Net is free software; you can redistribute it and/or modify
(*)		it under the terms of the Lesser GNU General Public License as published by
(*)		the Free Software Foundation; either version 2 of the License, or
(*)		(at your option) any later version.

(*)		OpenSmtp.Net is distributed in the hope that it will be useful,
(*)		but WITHOUT ANY WARRANTY; without even the implied warranty of
(*)		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
(*)		Lesser GNU General Public License for more details.

(*)		You should have received a copy of the Lesser GNU General Public License
(*)		along with this program; if not, write to the Free Software
(*)		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
(*)	/*******************************************************************************/

(*)	using System;
(*)	using System.Security.Cryptography;
(*)	using System.Globalization;
(*)	using System.IO;
(*)	using System.Text;

	/// <summary>
	/// This Type is used to encode and decode files and strings using 
	/// MIME compatible encoding methods such as Base64 and quoted-printable
	/// </summary>
	internal class MailEncoder
	{

		private MailEncoder()
		{}
		/// <summary>Encodes a String using Base64 (see RFC 1521)</summary>
		/// <param name="s">string to be encoded</param>
		/// <example>
		/// <code>
		/// string base64EncodedText = MailEncoder.ConvertQP("ËÇÅÃ");
		/// </code>
		/// </example>
		/// <returns>Base64 encoded string</returns>
		internal static string ConvertToBase64(String s)
		{
			byte[] from = Encoding.ASCII.GetBytes(s.ToCharArray());
			string returnMsg = Convert.ToBase64String(from);

			return returnMsg;
		}
		

		/// <summary> Encodes a FileStream using Base64 (see RFC 1521)</summary>
		/// <param name="inputFilePath">UNC path to file that needs to be encoded</param>
		/// <param name="outputFilePath">UNC path to file will store Base64 encoded ASCII text</param>
		/// <example>
		/// <code>
		/// MailEncoder.ConvertBase64("file.jpg", "file.txt");
		/// </code>
		/// </example>
		internal static void ConvertToBase64(string inputFilePath, string outputFilePath)
		{
			//Create the file streams to handle the input and output files.
			FileStream fin = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read);
(+)
(+)
(+)
(+)
(+)
(+)
(+)
(+)
(+)
(+)
(+)
(+)
(+)
(+)
(+)
			FileStream fout = new FileStream(outputFilePath, FileMode.OpenOrCreate, FileAccess.Write);
			fout.SetLength(0);

			ToBase64Transform transformer = new ToBase64Transform();

			//Create variables to help with read and write below.
			//This is intermediate storage for the encryption:
(*)			byte[] bin = new byte[fin.Length / transformer.InputBlockSize * transformer.OutputBlockSize]; 
			long rdlen = 0;              //This is the total number of bytes written.
(*)			long totlen = fin.Length;    //This is the total length of the input file.
			int len;                     //This is the number of bytes to be written at a time.

			CryptoStream encStream = new CryptoStream(fout, transformer, CryptoStreamMode.Write);

			//Read from the input file, then encrypt and write to the output file.
			while(rdlen < totlen)
			{
(*)				len = fin.Read(bin, 0, (int)fin.Length);
				encStream.Write(bin, 0, len);
				//inputBlock size(3)
				rdlen = (rdlen + ((len / transformer.InputBlockSize) * transformer.OutputBlockSize));
			}

			encStream.Close();
			fout.Close();
(-)			fin.Close();
		}
(*)
		internal static string ConvertFromBase64(string s)
		{
(*)			byte[] ret = Convert.FromBase64String(s);
(*)			return Encoding.ASCII.GetString(ret, 0, ret.Length);
		}
		
		internal static void ConvertFromBase64(string inputFilePath, string outputFilePath)
		{
			//Create the file streams to handle the input and output files.
			FileStream fin = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read);
			FileStream fout = new FileStream(outputFilePath, FileMode.OpenOrCreate, FileAccess.Write);
			fout.SetLength(0);

			FromBase64Transform transformer = new FromBase64Transform();

			//Create variables to help with read and write below.
			//This is intermediate storage for the decryption:
			byte[] bin = new byte[fin.Length / transformer.InputBlockSize * transformer.OutputBlockSize]; 
			long rdlen = 0;              //This is the total number of bytes written.
			long totlen = fin.Length;    //This is the total length of the input file.
			int len;                     //This is the number of bytes to be written at a time.

			CryptoStream encStream = new CryptoStream(fout, transformer, CryptoStreamMode.Write);

			//Read from the input file, then decrypt and write to the output file.
			while(rdlen < totlen)
			{
				len = fin.Read(bin, 0, (int)fin.Length);
				encStream.Write(bin, 0, len);
				rdlen = (rdlen + ((len / transformer.InputBlockSize) * transformer.OutputBlockSize));
			}

			encStream.Close();
			fout.Close();
			fin.Close();
		}
			
		/// <summary> Encodes a string using Quoted-Printable encoding (see RFC 1521)</summary>
		/// <param name="s">string that needs to be encoded</param>
(-)		/// <param name="charset">Charset</param>
		/// <example>
		/// <code>
		/// string qpEncodedText = MailEncoder.ConvertQP("ËÇÅÃ");
		/// </code>
		/// </example>
		/// <returns>Quoted-Printable encoded string</returns>
(*)		internal static string ConvertToQP(string s, string charset)
		{
			if (s == null) {return null;}

			char[] map = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
			
			// environment newline char
			char[] nl = Environment.NewLine.ToCharArray();			

			// source char array
			char[] source = s.ToCharArray();

			// result char array
			char[] result = new char[(int)(s.Length * 2)];

			
			// check for newline char
			char ch;
			int didx = 1,
(*)				cnt	 = 0;
			
			StringBuilder sb = new StringBuilder();
(-)			Encoding oEncoding = Encoding.GetEncoding(charset);
		
			for(int sidx=0; sidx < s.Length; sidx++)
			{
(*)				ch = Convert.ToChar(source[sidx]);
						
				// RULE # 4
				if (ch == nl[0])
				{
					// if char is preceded by space char add =20
					// RULE #3
					if (result[didx-1] == ' ')
					{
						sb.Append("=20");
					}
					
					// if char is preceded by tab char add =20
					// RULE #3
					if (result[didx-1] == '\t')
					{
						sb.Append("=90");
					}
					
					sb.Append("\r\n");
					sidx += nl.Length - 1;
					cnt = didx;

				}
(*)					// RULE #1 and #2
(*)				else if(ch > 126 || (ch < 32 && ch != '\t') || ch == '=' || ch == '?')
				{
(*)					byte[] outByte = new byte[10];
(*)					int iCount = oEncoding.GetBytes("" + ch, 0, 1, outByte, 0 );
(*)
(*)					for(int i = 0; i < iCount; i ++)
(*)					{
(*)						sb.Append( "=" + Convert.ToString( outByte[i], 16 ));
(*)					}
(*)
(*)					//sb.Append("=" + Convert.oString((byte)ch, 16));
				}
				else
				{
					sb.Append(ch);
					
					// RULE #5
					if (didx > cnt+70)
					{
						sb.Append("=\r\n");
						cnt = didx;
					}
				}
			}
			
			return sb.ToString();
		}

		internal static string ConvertHeaderToQP(string s, string charset)
		{
			
(*)			return "=?" + charset + "?Q?" + ConvertToQP(s, charset) + "?=";
		}

		internal static string ConvertFromQP(string s)
		{
			if (s == null) return null;
		
			// source char array:
			char[] source = s.ToCharArray();
			// result char array:
			char[] result = new char[(int)(s.Length*1.1)];
			// environment newline char:
			char[] nl = Environment.NewLine.ToCharArray();		
			
			int last = 0,
				didx = 0,
				slen = (int)s.Length;
			
			for ( int sidx = 0; sidx<slen; )
			{
				char ch = source[sidx++];
				
(*)				if (ch == '=') 
(*)				{	

					// Premature EOF
					if ( sidx >= slen-1 )
					{ throw new ParseException("Premature EOF"); }
				
					// RULE # 5
(*)					if ( source[sidx] == '\n' || source[sidx] == '\r' ) 
(*)					{
						sidx++;
(*)						if ( source[sidx-1] == '\r' && source[sidx] == '\n' ) 
(*)						{
							sidx++;
						}
					}
(*)						// RULE # 1
(*)					else 
(*)					{
						char repl;
						int hi = Int32.Parse(Convert.ToString(source[sidx]), NumberStyles.HexNumber);
						int lo = Int32.Parse(Convert.ToString(source[sidx+1]), NumberStyles.HexNumber);
						
(*)						if ( (hi | lo) < 0 ) 
(*)						{
							throw new ParseException(new String(source, sidx-1, 3) + " is an invalid code"); }
(*)						else 
(*)						{
							repl = (char) (hi << 4 | lo);
							sidx += 2;
						}
						
						result[didx++] = repl;
					}

					last = didx;
					
					// RULE # 4
(*)					if ( ch == '\n' || ch == '\r' ) 
(*)					{
(*)						if ( ch == '\r' && sidx < slen && source[sidx] == '\n' ) 
(*)						{
							sidx++;
						
(*)							for ( int idx=0; idx < nl.Length; idx++ ) 
(*)							{
								result[last++] = nl[idx];
								didx = last;
							}
						}
(*)						else 
(*)						{
							result[didx++]  =ch;
							// RULE # 3
(*)							if ( ch != ' ' && ch != '\t' ) 
(*)							{
								last = didx;
							}
						}
						
(*)						if ( didx > result.Length-nl.Length-2 ) 
(*)						{
							char[] newCharArray = new char[(int)(result.Length+500)];
							Array.Copy(result, newCharArray, result.Length);
							result = newCharArray;
						}
					}
					
				}
			}
			
			return new String(result, 0, didx);
		}

		internal static bool IsAscii(string s)
		{
(*)			// source char array
(*)			char[] source = s.ToCharArray();
(*)			for(int sidx=0; sidx < s.Length; sidx++)
(*)			{
(*)				char ch = source[sidx];
(*)				if (Convert.ToInt32(ch) > 127)
(*)				{
(*)					return false;
(*)				}
(*)			}

(*)			return true;
		}
		
	}
}